package org.baicaixiaozhan.learncommon.util.accesslimit;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.baicaixiaozhan.learncommon.exception.UnsatisfiedAccessLimiterRequestException;
import org.baicaixiaozhan.learncommon.util.DateTimeUtils;
import org.baicaixiaozhan.learncommon.util.HttpUtils;
import org.baicaixiaozhan.learncommon.util.SpringContextHandler;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;

import javax.servlet.http.HttpServletRequest;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * DESC:
 *
 * @since 2021-07-05
 * @author baicaixiaozhan
 */
@Slf4j
public class AccessWithIPLimiter implements AccessLimiter {

    private final RedisScript<Boolean> REDIS_SCRIPT = SpringContextHandler.getBean("accessWithIPLimiter", RedisScript.class);
    private final StringRedisTemplate stringRedisTemplate =  SpringContextHandler.getBean(StringRedisTemplate.class);

    @SneakyThrows(UnknownHostException.class)
    @Override
    public void startAccessLimit(long count, long timeOfMinutes) {
        HttpServletRequest request = HttpUtils.getRequest();
        LocalDateTime now = LocalDateTime.now();

        Long currEpochMilli = DateTimeUtils.toEpochMilli(now);
        Long epochMilliBeforeMinutes = DateTimeUtils.toEpochMilli(now.minusMinutes(timeOfMinutes));

        Boolean isAccess = stringRedisTemplate.execute(REDIS_SCRIPT,
                List.of("simple"),
                String.valueOf(count),
                String.valueOf(currEpochMilli),
                String.valueOf(epochMilliBeforeMinutes),
                HttpUtils.getIPAddress(request),
                UUID.randomUUID().toString());

        log.info("isAccess : {}", isAccess);
        if (!isAccess) {
            throw new UnsatisfiedAccessLimiterRequestException(String.format("当前时间下的当前 IP 超出访" +
                    "问次数，请%s分钟后再请求。", timeOfMinutes));
        }
    }
}
